using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Terra.Core.Constants;
using Microsoft.Extensions.Logging;
using System.Security.Claims;
using Terra.Core.Common.ApiResponse;
using Terra.Core.Common.ErrorCodes.Constants;
using System.Text.Json;

namespace Terra.Core.Security.Permissions;

/// <summary>
/// 权限验证处理器
/// </summary>
public class PermissionAuthorizationHandler : AuthorizationHandler<PermissionRequirement>
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly ILogger<PermissionAuthorizationHandler> _logger;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="httpContextAccessor">HTTP上下文访问器</param>
    /// <param name="logger">日志记录器</param>
    public PermissionAuthorizationHandler(IHttpContextAccessor httpContextAccessor, ILogger<PermissionAuthorizationHandler> logger)
    {
        _httpContextAccessor = httpContextAccessor;
        _logger = logger;
    }

    /// <summary>
    /// 处理权限验证
    /// </summary>
    /// <param name="context">授权上下文</param>
    /// <param name="requirement">权限要求</param>
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
    {
        if (context.User == null || !context.User.Identity.IsAuthenticated)
        {
            HandleUnauthorized();
            return Task.CompletedTask;
        }

        // 检查是否具有超级管理员角色或标记
        if (context.User.IsInRole(SecurityConstants.SuperAdminRoleCode) ||
            context.User.HasClaim(c => c.Type == "is_superadmin" && c.Value == "true"))
        {
            context.Succeed(requirement);
            return Task.CompletedTask;
        }

        // 获取当前用户的权限声明
        var permissions = context.User.Claims
            .Where(c => c.Type == SecurityConstants.PermissionClaimType)
            .Select(c => c.Value)
            .ToList();

        // 获取当前请求的权限编码
        var endpoint = _httpContextAccessor.HttpContext?.GetEndpoint();
        var actionDescriptor = endpoint?.Metadata.GetMetadata<ControllerActionDescriptor>();
        var permissionAttribute = actionDescriptor?.MethodInfo
            .GetCustomAttributes(true)
            .OfType<PermissionAttribute>()
            .FirstOrDefault();

        // 如果方法没有权限特性，则默认允许访问
        if (permissionAttribute == null)
        {
            context.Succeed(requirement);
            return Task.CompletedTask;
        }

        // 验证权限
        if (permissions.Contains(permissionAttribute.PermissionCode))
        {
            context.Succeed(requirement);
        }
        else
        {
            _logger.LogWarning(
                "用户 {UserId} 尝试访问未授权的资源。需要权限: {RequiredPermission}, 拥有权限: {UserPermissions}",
                context.User.FindFirst(ClaimTypes.NameIdentifier)?.Value,
                permissionAttribute.PermissionCode,
                string.Join(", ", permissions));

            HandleForbidden(permissionAttribute.PermissionCode);
        }

        return Task.CompletedTask;
    }

    /// <summary>
    /// 处理未授权访问
    /// </summary>
    private void HandleUnauthorized()
    {
        if (_httpContextAccessor.HttpContext != null)
        {
            var response = _httpContextAccessor.HttpContext.Response;
            response.StatusCode = StatusCodes.Status401Unauthorized;
            response.ContentType = "application/json";

            var result = ApiResponse.Error(SecurityErrorCodes.Unauthorized, "未经授权的访问");
            var jsonResponse = JsonSerializer.Serialize(result);
            response.WriteAsync(jsonResponse).Wait();
        }
    }

    /// <summary>
    /// 处理权限不足
    /// </summary>
    private void HandleForbidden(string requiredPermission)
    {
        if (_httpContextAccessor.HttpContext != null)
        {
            var response = _httpContextAccessor.HttpContext.Response;
            response.StatusCode = StatusCodes.Status403Forbidden;
            response.ContentType = "application/json";

            var result = ApiResponse.Error(
                SecurityErrorCodes.InsufficientPermissions,
                $"权限不足，需要权限：{requiredPermission}");
            var jsonResponse = JsonSerializer.Serialize(result);
            response.WriteAsync(jsonResponse).Wait();
        }
    }
}